// Copyright 2019 The rhyme_lph Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// s [author] rhyme_lph
// S [email]  rhymelph@gmail.com
// U [github] https://github.com/rhymelph

import 'dart:async';

import 'package:base_plugin/base_plugin.dart';
import 'package:dio/src/response.dart';
import 'package:finance_app/generated/l10n.dart';
import 'package:finance_app/src/common/config.dart';
import 'package:finance_app/src/entities/dashboard_reimburse_entity.dart';
import 'package:finance_app/src/entities/expanse_item_value.dart';
import 'package:finance_app/src/entities/expense_detail_entity.dart';
import 'package:finance_app/src/http_service/http_dashboard_service.dart';
import 'package:finance_app/src/http_service/http_expense_service.dart';
import 'package:finance_app/src/mixin/refresh_mixin.dart';
import 'package:finance_app/src/router_gen/router_gen_providers.dart';
import 'package:finance_app/src/utils/list_to_map_utils.dart';
import 'package:finance_app/src/utils/permission_utils.dart';
import 'package:flutter/material.dart';

import '../hr_and_payroll_provider.dart';

class ReimburseProvider extends BaseProvider<DashboardReimburseEntity>
    with RefreshMixin<DashboardReimburseEntity, List<ExpenseDetailEntity>> {
  Map<String, ExpanseItemValue> expanseMap = {
    'pending': ExpanseItemValue(isOpen: true),
    'now': ExpanseItemValue(),
    'rejected': ExpanseItemValue(),
  };
  String currentType = 'pending';
  List<String> typeList = ['pending', 'now', 'rejected'];
  ScrollController controller = ScrollController();

  @override
  void initState() {
    super.initState();
    expanseMap.entries.forEach((element) {
      element.value.controller.addListener(_handleExpanseListener);
    });
    controller.addListener(() {
      getParentProvider<HrAndPayrollProvider>().handleScrollUpdate(controller);
    });
  }

  @override
  Future get dataFuture => HttpDashboardService.dashboardReimburses();

  Future<void> loadDashboard() async {
    if (Config.hasPermission(PermissionUtils.hrPayroll)) {
      await post(dataFuture, autoHandler: AutoHandler.Toast,
          onSuccess: (result) {
        data = getEntityFromResult<DashboardReimburseEntity>(result);
        if (!canRefreshFuture) {
          update();
        }
      });
    }
  }

  void onChangeType(String type) {
    currentType = type;
    _loadExpend(isShowLoading: true);
  }

  void _handleExpanseListener() {
    bool hasOpen = false;
    String key;
    for (final item in expanseMap.entries) {
      if (item.value.controller.value == true) {
        hasOpen = true;
        key = item.key;
        break;
      }
    }
    if (hasOpen == true) {
      onChangeType(key);
    } else {
      // expanseMap[currentType].allData = null;
      expanseMap[currentType].groupMap.clear();
      currentType = null;
      update();
    }
  }

  @override
  void addData(List<ExpenseDetailEntity> data, bool isRefresh) {
    if (isRefresh) {
      expanseMap[currentType].allData = data;
    } else {
      expanseMap[currentType].allData.addAll(data);
    }
  }

  @override
  FutureOr<DashboardReimburseEntity> transformData(
      DashboardReimburseEntity d, bool isCache) async {
    await _loadExpend();
    return super.transformData(d, isCache);
  }

  Future<void> _loadExpend({bool isShowLoading = false}) async {
    page = 1;
    await post(refreshFuture,
        autoHandler: AutoHandler.Toast,
        loadingTip: isShowLoading ? S.current.loading : null,
        onSuccess: (result) {
      expanseMap[currentType].allData =
          getEntityFromResult<List<ExpenseDetailEntity>>(result);
      hasUp = expanseMap[currentType].allData.length >= rows;
      contactToMap(expanseMap[currentType].allData);
      update();
    });
  }

  void contactToMap(List<ExpenseDetailEntity> payslipsList) {
    Map<String, List<ExpenseDetailEntity>> groupMap =
        expanseMap[currentType].groupMap;

    for (final item in payslipsList) {
      final month = ListToMapUtils.groupMonth<ExpenseDetailEntity>(
          item, (t) => t.issuedAt);
      if (groupMap.containsKey(month)) {
        groupMap[month].add(item);
      } else {
        groupMap[month] = [item];
      }
    }
  }

  String getGroupName(String key) {
    if (key == 'pending') {
      return S.current.pending_reimbursements;
    } else if (key == 'now') {
      return S.current.approved_reimbursements;
    } else if (key == 'rejected') {
      return S.current.rejected_reimbursements;
    } else if (key == 'later') {
      return S.current.added_reimbursements;
    } else {
      return key;
    }
  }

  void onNavDetail(ExpenseDetailEntity e) async {
    final result =
        await Routes.navigateTo(RouterGenProviders.newExpensePage, params: {
      'expenseData': e,
      'isHidePaid': true,
      'isSelectMode': true,
    });
    if (result != null && result is bool) {
      expanseMap[currentType].allData.remove(e);
      expanseMap[currentType].groupMap.clear();
      contactToMap(expanseMap[currentType].allData);
      update();
    }
    // else if (result != null && result is ExpenseDetailEntity) {
    //   e.fromJson(result.toJson());
    //   expanseMap[currentType].groupMap.clear();
    //   contactToMap(expanseMap[currentType].allData);
    //   update();
    // }
  }

  @override
  List<ExpenseDetailEntity> get dataList =>
      currentType == null ? [] : expanseMap[currentType].allData;

  @override
  List<ExpenseDetailEntity> getFromRequestResult(
      Response<dynamic> result, bool isRefresh) {
    List<ExpenseDetailEntity> list =
        getEntityFromResult<List<ExpenseDetailEntity>>(result);
    if (isRefresh) {
      // expanseMap[currentType].allData = list;
      expanseMap[currentType].groupMap.clear();
    } else {
      // expanseMap[currentType].allData.addAll(list);
      // expanseMap[currentType].groupMap.clear();
    }
    contactToMap(list);
    return list;
  }

  @override
  Future get refreshFuture =>
      HttpExpenseService.reimbursementsList(currentType, page);

  void deleteData(int id) {
    if (id == null) return;
    expanseMap[currentType].allData.removeWhere((element) => element.id == id);
    expanseMap[currentType].groupMap.clear();
    contactToMap(expanseMap[currentType].allData);
    update();
  }

  @override
  Future<void> onRefresh() async {
    await loadDashboard();
    return super.onRefresh();
  }

  @override
  bool get canRefreshFuture => currentType != null;

// //更新Date
  void updateData(ExpenseDetailEntity data) {
    final finder = expanseMap[currentType]
        .allData
        .firstWhere((element) => element.id == data.id, orElse: () => null);
    if (finder != null) {
      if (data.reimburseStatus != currentType) {
        expanseMap[currentType].allData.remove(data);
        dataList.remove(data);
      } else {
        finder.fromJson(data.toJson());
      }
    } else if (data.reimburseStatus == currentType) {
      expanseMap[currentType].allData.add(data);
    }
    expanseMap[currentType].groupMap.clear();
    contactToMap(expanseMap[currentType].allData);
    update();
  }
}
